﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.ExceptionServices;
using System.Threading;

namespace NDK.Motion.Card
{

    //凌华运动控制卡
    [Serializable]
    public class Adlink833X : IMotionCard, IOCard
    {
        private static log4net.ILog traceLogger = log4net.LogManager.GetLogger("Adlink");

        #region fileds/properties
        private string _cardName;
        private int _cardID;
        private int _totalAxis;
        private int _inputCount;
        private int _outputCount;
        private string _adlinkCardType;
        private int _startAxisID;
        [NonSerialized]
        private bool _initialized;
        public string CardName
        {
            get
            {
                return _cardName;
            }

            set
            {
                _cardName = value;
            }
        }

        public int CardID
        {
            get
            {
                return _cardID;
            }

            set
            {
                _cardID = value;
            }
        }

        public int TotalAxis
        {
            get
            {
                return _totalAxis;
            }

            set
            {
                _totalAxis = value;
            }
        }

        public int InputCount
        {
            get
            {
                return _inputCount;
            }

            set
            {
                _inputCount = value;
            }
        }

        public int OutputCount
        {
            get
            {
                return _outputCount;
            }

            set
            {
                _outputCount = value;
            }
        }

        public string CardType
        {
            get
            {
                return _adlinkCardType;
            }

            set
            {
                _adlinkCardType = value;
            }
        }

        public int StartAxisID
        {
            get
            {
                return _startAxisID;
            }

            set
            {
                _startAxisID = value;
            }
        }

        public bool Initialized
        {
            get
            {
                return _initialized;
            }

            set
            {
                _initialized = value;
            }
        }

        public const int ON = 1;
        public const int OFF = 0;

       
        #endregion
        /// <summary>
        /// 初始化凌华板卡,mode默认为0（Card ID by system assigned）
        /// </summary>
        /// <param name="motionCards"></param>
        /// <param name="mode">
        /// * 00 0 0 0 0
        /// Bit0: Enable the On board dip switch (SW1) to decide the Card ID. [0:By system assigned, 1:By dip switch]
        /// Bit1: Parallel type axis indexing mode 0 : auto mode (default) 1 : fixed mode（普通卡，并行类型）
        /// Bit2: Serial type axis indexing mode 0: auto mode (default) 1: fixed mode （总线卡，串行类型）
        /// Bit4: Option of load  system & axes parameters method
        /// Bit5: (00B) 0: Do nothing, parameters keep current value. (01B) 1:Load from default. (02B)2:Load from flash.
        /// others: Reserved
        /// </param>
        /// <returns></returns>
        //public bool CardInit(out List<ICard> motionCards, Int32 mode = 0)
        //{
        //    //Card ID information in bit format. 
        //    //Example: If the value of BoardID_InBits is 0x11 which means that there are 2 cards in your system and those card‘s ID are 0 and 4. 
        //    Int32 boardID_InBits = 0;
        //    Int32 ret = 0;
        //    Int32 i = 0;
        //    Int32 card_name = 0;
        //    Int32 temp = 0;
        //    Int32 startAxisID = 0;
        //    Int32 totalAxisNum = 0;
        //    motionCards = new List<ICard>();
        //    try
        //    {
        //        // Card(Board) initial
        //        ret = APS168.APS_initial(ref boardID_InBits, mode);
        //        //if init success,load param file 
        //        if (ret == 0)
        //        {
        //            for (i = 0; i < 16; i++)//搜索0~15bit
        //            {
        //                temp = (boardID_InBits >> i) & 1;
        //                if (temp == 1)
        //                {
        //                    APS168.APS_get_card_name(i, ref card_name);
        //                    if (card_name == (Int32)APSDefine.DEVICE_NAME_PCI_825458
        //                        || card_name == (Int32)APSDefine.DEVICE_NAME_AMP_20408C)
        //                    {
        //                        ret = APS168.APS_get_first_axisId(i, ref startAxisID, ref totalAxisNum);
        //                        Adlink card = new Adlink();
        //                        card.CardID = i;
        //                        card.CardType = ((ADLINK_CARD_TYPE)card_name).ToString();
        //                        card.TotalAxis = totalAxisNum;
        //                        card.InputCount = 24;
        //                        card.OutputCount = 24;
        //                        card.StartAxisID = startAxisID;
        //                        card.Initialized = true;
        //                        motionCards.Add(card);
        //                        //加载轴配置文件
        //                        card.LoadParamFile(Environment.CurrentDirectory + @"\Config\Param" + i.ToString() + ".xml", motionCards[i].CardID);
        //                    }
        //                }
        //            }
        //        }
        //        else
        //        {
        //            return false;
        //        }
        //    }
        //    catch (Exception ex)
        //    {
        //        throw new Exception("Adlink CardInit Exception:" + ex.StackTrace);
        //    }
        //    return true;
        //}
        //833X
        [HandleProcessCorruptedStateExceptions]
        public bool CardInit(ref List<ICard> motionCards, Int32 mode = 0)
        {
            //Card ID information in bit format. 
            //Example: If the value of BoardID_InBits is 0x11 which means that there are 2 cards in your system and those card‘s ID are 0 and 4. 
            Int32 boardID_InBits = 0;
            Int32 ret = 0;
            Int32 card_name = 0;
            Int32 temp = 0;
            Int32 startAxisID = 0;
            Int32 totalAxisNum = 0;
            try
            {
                // Card(Board) initial
                Finalize();
                ret = APS168.APS_initial(ref boardID_InBits, mode);
                //if init success,load param file 
                if (ret == (int)APSDefine.ERR_NoError)
                {
                    for (int boardID = 0; boardID < 16; boardID++)//搜索0~15bit
                    {
                        temp = (boardID_InBits >> boardID) & 1;
                        if (temp == 1)
                        {
                            APS168.APS_get_card_name(boardID, ref card_name);
                            if (card_name == (Int32)APSDefine.DEVICE_NAME_PCIE_8338
                                || card_name == (Int32)APSDefine.DEVICE_NAME_PCIE_8334
                                || card_name == (Int32)APSDefine.DEVICE_NAME_PCIE_8332)
                            {
                                //搜索到一张卡
                                ret += APS168.APS_get_first_axisId(boardID, ref startAxisID, ref totalAxisNum);
                                APS168.APS_scan_field_bus(boardID, 0);
                                ret += APS168.APS_start_field_bus(boardID, 0, startAxisID);
                                if (ret == (int)APSDefine.ERR_NoError)
                                {
                                    Adlink833X card = new Adlink833X();
                                    card.CardID = boardID;
                                    card.CardType = "Adlink_833X";
                                    card.TotalAxis = totalAxisNum;
                                    card.StartAxisID = startAxisID;
                                    //搜索总线下的模块，得到总的IO个数
                                    int slaveNum = -1, count = 0;
                                    if (APS168.APS_get_field_bus_last_scan_info(boardID, 0, ref slaveNum, 1, ref count) == (int)APSDefine.ERR_NoError)
                                    {
                                        for (int slave = 0; slave < slaveNum; slave++)
                                        {
                                            EC_MODULE_INFO[] module_info = new EC_MODULE_INFO[1];
                                            ret += APS168.APS_get_field_bus_module_info(boardID, 0, slave, module_info);
                                            if (ret == (int)APSDefine.ERR_NoError)
                                            {
                                                if (module_info[0].DI_ModuleNum >= 1) card.InputCount += module_info[0].DI_ModuleNum;
                                                if (module_info[0].DO_ModuleNum >= 1) card.OutputCount += module_info[0].DO_ModuleNum;
                                            }
                                        }
                                    }

                                    card.Initialized = true;
                                    motionCards.Add(card);
                                    //加载轴配置文件
                                    card.LoadParamFile(Environment.CurrentDirectory + @"\Config\Param" + boardID.ToString() + ".xml", motionCards[boardID].CardID);
                                }
                            }
                        }
                    }
                }
                else
                {
                    return false;
                }
            }
            catch (Exception ex)
            {
                throw new Exception("Adlink CardInit Exception:" + ex.StackTrace);
            }
            return true;
        }

        public bool CardInit(int mode = 0)
        {
            //Card ID information in bit format. 
            //Example: If the value of BoardID_InBits is 0x11 which means that there are 2 cards in your system and those card‘s ID are 0 and 4. 
            Int32 boardID_InBits = 0;
            Int32 ret = 0;
            Int32 card_name = 0;
            Int32 temp = 0;
            Int32 startAxisID = 0;
            Int32 totalAxisNum = 0;
            try
            {
                // Card(Board) initial
                ret = APS168.APS_initial(ref boardID_InBits, mode);
                //if init success,load param file 
                if (ret == (int)APSDefine.ERR_NoError)
                {
                    APS168.APS_get_card_name(CardID, ref card_name);
                    if (card_name == (Int32)APSDefine.DEVICE_NAME_PCIE_8338
                        || card_name == (Int32)APSDefine.DEVICE_NAME_PCIE_8334
                        || card_name == (Int32)APSDefine.DEVICE_NAME_PCIE_8332)
                    {
                        //搜索到一张卡
                        ret += APS168.APS_get_first_axisId(CardID, ref startAxisID, ref totalAxisNum);
                        APS168.APS_scan_field_bus(CardID, 0);
                        ret += APS168.APS_start_field_bus(CardID, 0, startAxisID);
                        if (ret == (int)APSDefine.ERR_NoError)
                        {
                            this.Initialized = true;
                            //加载轴配置文件
                            this.LoadParamFile(Environment.CurrentDirectory + @"\Config\Param" + CardID.ToString() + ".xml", this.CardID);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                throw new Exception("Adlink833X CardInit Exception:" + ex.StackTrace);
            }
            return true;
        }


        //7856
        //public bool CardInit(out List<ICard> cards, Int32 mode = 0)
        //{
        //    Int32 boardID_InBits = 0;
        //    //Int32 mode = 0;
        //    Int32 ret = 0;
        //    Int32 card_name = 0;
        //    int startAxisID = 0;
        //    int totalAxisNum = 0;
        //    Adlink card = new Adlink();
        //    cards = new List<ICard>();

        //    // Card(Board) initial
        //    ret += APS168.APS_close();
        //    ret += APS168.APS_initial(ref boardID_InBits, mode);

        //    //if init success,load param file 
        //    if (ret == 0)
        //    {
        //        ret += APS168.APS_stop_field_bus(0, 0);
        //        ret += APS168.APS_set_field_bus_param(0, 0, (Int32)APSDefine.PRF_HUB_NUMBER, 1);

        //        ret += APS168.APS_set_field_bus_param(0, 0, (Int32)APSDefine.PRF_TRANSFER_RATE, 3);
        //        ret += APS168.APS_start_field_bus(0, 1, 1500);//axis lianjie
        //        ret += APS168.APS_start_field_bus(0, 0, 0); //io lianjie

        //        ret = APS168.APS_get_first_axisId(0, ref startAxisID, ref totalAxisNum);

        //        card = new Adlink();
        //        card.CardID = 0;
        //        card.CardType = ((ADLINK_CARD_TYPE)card_name).ToString();
        //        card.TotalAxis = totalAxisNum;
        //        card.InputCount = 0;
        //        card.OutputCount = 0;
        //        card.StartAxisID = startAxisID;
        //        card.Initialized = true;
        //        cards.Add(card);

        //        if (ret == 0)
        //        {
        //            LoadParamFile(Environment.CurrentDirectory + @"\Config\Param0.xml", 0);
        //            Common.AppendUiLog.Log("Motion card " + 0 + " intial ok...", LogType.Info);
        //            Common.isCardInitialed = true;
        //        }
        //    }
        //    else
        //    {
        //        //m_Logger.Error("设置轴参数失败");
        //        Common.isCardInitialed = false;
        //        return false;
        //    }
        //    return true;
        //}
        /// <summary>
        /// 加载控制卡配置文件
        /// </summary>
        /// <param name="filePath">配置文件绝对路径</param>
        /// <returns></returns>
        [HandleProcessCorruptedStateExceptions]
        public bool LoadParamFile(string filePath, int boardId)
        {
            int? ret = null;
            try
            {
                if (File.Exists(filePath))
                {
                    ret = APS168.APS_load_param_from_file(filePath);
                    if (ret != 0)
                    {
                        //m_Logger.Error("加载板卡配置文件失败");
                        return false;
                    }
                }
            }
            catch (Exception e)
            {
                traceLogger.Error("加载板卡配置文件失败" + e.Message);
                return false;
            }
            return true;
        }
        /// <summary>
        /// 获取指定位置，电机状态
        /// </summary>
        /// <param name="AxisId">轴ID</param>
        /// <returns></returns>
        [HandleProcessCorruptedStateExceptions]
        public bool GetMotionStatus(short axisId, int motionStatusBit)
        {
            int? status = null;
            try
            {
                status = (APS168.APS_motion_status(axisId) >> motionStatusBit) & 1;

                if (status == 1)
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
            catch (Exception ex)
            {
                throw new Exception("Adlink GetMotionStatus Exception! " + ex.StackTrace);
            }
        }

        [HandleProcessCorruptedStateExceptions]
        public bool GetASTPStatus(short axisId)
        {
            try
            {
                return GetMotionStatus(axisId, (int)ADLINK_MOTION_STATUS_ENUM.MTS_ASTP);
            }
            catch (Exception ex)
            {
                throw new Exception("Adlink GetASTPStatus Exception! " + ex.StackTrace);
            }
        }
        [HandleProcessCorruptedStateExceptions]
        public bool GetHMVStatus(short axisId)
        {
            try
            {
                return GetMotionStatus(axisId, (int)ADLINK_MOTION_STATUS_ENUM.MTS_HMV);
            }
            catch (Exception ex)
            {
                throw new Exception("Adlink GetHMVStatus Exception! " + ex.StackTrace);
            }
        }
        [HandleProcessCorruptedStateExceptions]
        public bool GetNSTPStatus(short axisId)
        {
            try
            {
                return GetMotionStatus(axisId, (int)ADLINK_MOTION_STATUS_ENUM.MTS_NSTP);
            }
            catch (Exception ex)
            {
                throw new Exception("Adlink GetNSTPStatus Exception! " + ex.StackTrace);
            }
        }
        [HandleProcessCorruptedStateExceptions]
        public bool GetCSTPStatus(short axisId)
        {
            try
            {
                return GetMotionStatus(axisId, (int)ADLINK_MOTION_STATUS_ENUM.MTS_CSTP);
            }
            catch (Exception ex)
            {
                throw new Exception("Adlink GetCSTPStatus Exception! " + ex.StackTrace);
            }
        }
        /// <summary>
        /// 获取电机IO状态
        /// </summary>
        /// <param name="AxisId">轴ID</param>
        /// <returns></returns>
        [HandleProcessCorruptedStateExceptions]
        public bool GetMotionIoSatus(short axisId, int motionIoStatusBit)
        {
            int motionIoStatus = 0;
            try
            {
                motionIoStatus = APS168.APS_motion_io_status(axisId);
                motionIoStatus = (motionIoStatus >> motionIoStatusBit) & 1;
                if (motionIoStatus == 1)
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
            catch (Exception ex)
            {
                throw new Exception("Adlink GetMotionIoSatus Exception! " + ex.StackTrace);
            }
        }

        [HandleProcessCorruptedStateExceptions]
        public bool GetORGStatus(short axisId)
        {
            try
            {
                return GetMotionIoSatus(axisId, (int)ADLINK_MOTION_IO_STATUS_ENUM.MIO_ORG);
            }
            catch (Exception ex)
            {
                throw new Exception("Adlink GetORGStatus Exception! " + ex.StackTrace);
            }
        }
        [HandleProcessCorruptedStateExceptions]
        public bool GetMELStatus(short axisId)
        {
            try
            {
                return GetMotionIoSatus(axisId, (int)ADLINK_MOTION_IO_STATUS_ENUM.MIO_MEL);
            }
            catch (Exception ex)
            {
                throw new Exception("Adlink GetMELStatus Exception! " + ex.StackTrace);
            }
        }
        [HandleProcessCorruptedStateExceptions]
        public bool GetPELStatus(short axisId)
        {
            try
            {
                return GetMotionIoSatus(axisId, (int)ADLINK_MOTION_IO_STATUS_ENUM.MIO_PEL);
            }
            catch (Exception ex)
            {
                throw new Exception("Adlink GetPELStatus Exception! " + ex.StackTrace);
            }
        }
        [HandleProcessCorruptedStateExceptions]
        public bool GetINPStatus(short axisId)
        {
            try
            {
                return GetMotionIoSatus(axisId, (int)ADLINK_MOTION_IO_STATUS_ENUM.MIO_INP);
            }
            catch (Exception ex)
            {
                throw new Exception("Adlink GetINPStatus Exception! " + ex.StackTrace);
            }
        }
        public bool GetEMGStatus(short axisId)
        {
            try
            {
                return GetMotionIoSatus(axisId, (int)ADLINK_MOTION_IO_STATUS_ENUM.MIO_EMG);
            }
            catch (Exception ex)
            {
                throw new Exception("Adlink GetEMGStatus Exception! " + ex.StackTrace);
            }
        }
        public bool GetALMStatus(short axisId)
        {
            try
            {
                return GetMotionIoSatus(axisId, (int)ADLINK_MOTION_IO_STATUS_ENUM.MIO_ALM);
            }
            catch (Exception ex)
            {
                throw new Exception("Adlink GetALMStatus Exception! " + ex.StackTrace);
            }
        }
        public bool GetServoOnStatus(short axisId)
        {
            try
            {
                return GetMotionIoSatus(axisId, (int)ADLINK_MOTION_IO_STATUS_ENUM.MIO_SVON);
            }
            catch (Exception ex)
            {
                throw new Exception("Adlink GetServoOnStatus Exception! " + ex.StackTrace);
            }
        }




        /// <summary>
        /// 获取电机实际位置（轴反馈）
        /// This function is used to get the position counter of one axis. The counter is in unit of pulse. 
        /// </summary>
        /// <param name="axisId">轴ID</param>
        /// <param name="position">实际位置</param>
        /// <returns></returns>
        [HandleProcessCorruptedStateExceptions]
        public bool GetFeedbackPosition(short axisId, ref double feedbackPosition)
        {
            int ret = 0;
            try
            {
                ret = APS168.APS_get_position_f(axisId, ref feedbackPosition);
                if (ret != 0)
                {
                    return false;
                }
            }
            catch (Exception ex)
            {
                throw new Exception("Adlink GetFeedbackPosition Exception! " + ex.StackTrace);
            }
            return true;
        }
        [HandleProcessCorruptedStateExceptions]
        public bool GetCmdPosition(short axisId, ref double commandPosition)
        {
            int ret = 0;
            try
            {
                ret = APS168.APS_get_command_f(axisId, ref commandPosition);
                if (ret != 0)
                {
                    return false;
                }
            }
            catch (Exception ex)
            {
                throw new Exception("Adlink GetCmdPosition Exception! " + ex.StackTrace);
            }
            return true;
        }
        [HandleProcessCorruptedStateExceptions]
        public bool GetTargetPosition(short axisId, ref double targetPosition)
        {
            int ret = 0;
            try
            {
                ret = APS168.APS_get_target_position_f(axisId, ref targetPosition);
                if (ret != 0)
                {
                    return false;
                }
            }
            catch (Exception ex)
            {
                throw new Exception("Adlink GetTargetPosition Exception! " + ex.StackTrace);
            }
            return true;
        }
        [HandleProcessCorruptedStateExceptions]
        public bool GetErrorPosition(short axisId, ref double errorPosition)
        {
            int ret = 0;
            try
            {
                ret = APS168.APS_get_error_position_f(axisId, ref errorPosition);
                if (ret != 0)
                {
                    return false;
                }
            }
            catch (Exception ex)
            {
                throw new Exception("Adlink GetErrorPosition Exception! " + ex.StackTrace);
            }
            return true;
        }
        [HandleProcessCorruptedStateExceptions]
        public bool GetFeedbackVelocity(short axisId, ref double feedbackVelocity)
        {
            int ret = 0;
            try
            {
                ret = APS168.APS_get_feedback_velocity_f(axisId, ref feedbackVelocity);
                if (ret != 0)
                {
                    return false;
                }
            }
            catch (Exception ex)
            {
                throw new Exception("Adlink GetErrorPosition Exception! " + ex.StackTrace);
            }
            return true;
        }
        /// <summary>
        /// 指定轴归零
        /// </summary>
        /// <param name="axisId">轴ID</param>
        /// <param name="homeMode">回零模式</param>
        /// <param name="homeDir">搜索方向</param>
        /// <param name="homeCure">曲线</param>
        /// <param name="homeAcc">回零加速度</param>
        /// <param name="homeVm">回零最大速度</param>
        /// <param name="homeVo">回零初速度</param>
        /// <param name="homeShiftDistance">回零偏移</param>
        /// <param name="stopDec">停止减速度</param>
        /// <param name="isEnableSoftLimit">是否使能软限位</param>
        /// <param name="spelPos">正软限位位置</param>
        /// <param name="smelPos">负软限位位置</param>
        /// <returns></returns>
        [HandleProcessCorruptedStateExceptions]
        public bool HomeMove(short axisId, PRA_HOME_ENUM homeMode, DIR_ENUM homeDir, PRA_SF_ENUM homeCure, double homeAcc, double homeVm, double homeVo, double homeShiftDistance, double stopDec, SWITCH_ENUM isEnableSoftLimit, double spelPos, double smelPos)
        {
            int? ret = 0;
            try
            {
                // 1. Select home mode and config home parameters 
                ret += APS168.APS_set_axis_param(axisId, (Int32)APSDefine.PRA_HOME_MODE, (int)homeMode); // Set home mode
                ret += APS168.APS_set_axis_param(axisId, (Int32)APSDefine.PRA_HOME_DIR, (int)homeDir); // Set home direction
                ret += APS168.APS_set_axis_param(axisId, (Int32)APSDefine.PRA_HOME_CURVE, (int)homeCure); // Set acceleration paten（0 --> 1：T --> S）
                ret += APS168.APS_set_axis_param_f(axisId, (Int32)APSDefine.PRA_HOME_ACC, homeAcc); // Set homing acceleration rate
                ret += APS168.APS_set_axis_param_f(Convert.ToInt16(axisId), (Int32)APSDefine.PRA_HOME_VM, homeVm); // Set homing maximum velocity.
                ret += APS168.APS_set_axis_param_f(Convert.ToInt16(axisId), (Int32)APSDefine.PRA_HOME_VO, homeVm); // Set homing VO speed
                ret += APS168.APS_set_axis_param(Convert.ToInt16(axisId), (Int32)APSDefine.PRA_HOME_EZA, 0); // Set EZ signal alignment (yes or no)
                ret += APS168.APS_set_axis_param_f(Convert.ToInt16(axisId), (Int32)APSDefine.PRA_HOME_SHIFT, homeShiftDistance); // Set home position shfit distance. 
                ret += APS168.APS_set_axis_param_f(Convert.ToInt16(axisId), (Int32)APSDefine.PRA_HOME_POS, 0); // Set final home position.


                ret += APS168.APS_set_axis_param_f(Convert.ToInt16(axisId), (Int32)APSDefine.PRA_SD_DEC, stopDec); // Set up rate for deceleration stop.
                ret += APS168.APS_set_axis_param(Convert.ToInt16(axisId), (Int32)APSDefine.PRA_SPEL_EN, (int)isEnableSoftLimit); // Soft PEL switch.
                ret += APS168.APS_set_axis_param(Convert.ToInt16(axisId), (Int32)APSDefine.PRA_SMEL_EN, (int)isEnableSoftLimit); // Soft MEL switch.
                ret += APS168.APS_set_axis_param_f(Convert.ToInt16(axisId), (Int32)APSDefine.PRA_SPEL_POS, spelPos); // Soft-PEL position.
                ret += APS168.APS_set_axis_param_f(Convert.ToInt16(axisId), (Int32)APSDefine.PRA_SMEL_POS, smelPos); // Soft-MEL position.

                ret += APS168.APS_set_servo_on(Convert.ToInt16(axisId), 1);
                ret += APS168.APS_home_move(Convert.ToInt16(axisId));
                if (ret != 0)
                {
                    return false;
                }
            }
            catch (Exception e)
            {
                return false;
            }
            return true;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="axisId"></param>
        /// <param name="dir"></param>
        /// <param name="acc"></param>
        /// <param name="dec"></param>
        /// <param name="vm"></param>
        /// <param name="SF"></param>
        /// <returns></returns>
        [HandleProcessCorruptedStateExceptions]
        public bool MoveVel(short axisId, DIR_ENUM dir, double acc, double dec, double vm, double SF = 0.5)
        {
            int ret = 0;
            ASYNCALL p = new ASYNCALL();
            try
            {
                ret += APS168.APS_set_axis_param_f(axisId, (Int32)APSDefine.PRA_STP_DEC, dec);
                ret += APS168.APS_set_axis_param_f(axisId, (Int32)APSDefine.PRA_CURVE, 0.5); //Set acceleration rate
                ret += APS168.APS_set_axis_param_f(axisId, (Int32)APSDefine.PRA_ACC, acc); //Set acceleration rate
                ret += APS168.APS_set_axis_param_f(axisId, (Int32)APSDefine.PRA_DEC, dec); //Set deceleration rate

                ret += APS168.APS_vel(axisId, (int)dir, vm, ref p);
                if (ret != 0)
                {
                    return false;
                }
            }
            catch (Exception ex)
            {
                throw new Exception("MoveVel Exception! " + ex.StackTrace);
            }
            return true;

        }
        /// <summary>
        /// JOG到指定位置
        /// </summary>
        /// <param name="AxisId">轴ID</param>
        /// <param name="ApsOption">轴方向</param>
        /// <param name="vm">运行速度</param>
        /// <param name="acc">加减速</param>
        /// <param name="position">位置</param>
        /// <returns></returns>
        [HandleProcessCorruptedStateExceptions]
        public bool PTPMove(short axisId, PRA_OPTION_ENUM ApsOption, double vm, double acc, double dec, double position)
        {
            int ret = 0;
            ASYNCALL Wait = new ASYNCALL();
            try
            {
                // Config speed profile parameters.
                ret += APS168.APS_set_axis_param_f(axisId, (Int32)APSDefine.PRA_SF, 0.5);
                ret += APS168.APS_set_axis_param_f(axisId, (Int32)APSDefine.PRA_ACC, acc);
                ret += APS168.APS_set_axis_param_f(axisId, (Int32)APSDefine.PRA_DEC, dec);
                ret += APS168.APS_set_axis_param_f(axisId, (Int32)APSDefine.PRA_VM, vm);
                //APS_ptp:This function is used to execute a single move by axis. 
                //No any suffix represents that no any motion profile is necessary to perform a single move. 
                //Other motion profiles are set in axis parameters. 
                ret += APS168.APS_ptp(axisId, Convert.ToInt16(ApsOption), position, ref Wait);

                //APS_ptp
                //This function is used to execute a single move by axis.
                //The _v suffix represents that only one motion profile, that is Vm, 
                //is necessary to perform a single move.Other motion profiles are set in axis parameters.
                //ret += APS168.APS_ptp_v(axisId, Convert.ToInt16(ApsOption), position,vm, ref Wait);

                if (ret != 0)
                {
                    return false;
                }
            }
            catch (Exception ex)
            {
                throw new Exception("Axis[" + axisId + "] ,Adlink PTPMove Exception!" + ex.StackTrace);
            }
            return true;
        }
        [HandleProcessCorruptedStateExceptions]
        public bool Finalize()
        {
            try
            {
                APS168.APS_stop_field_bus(0, 0);
                if (APS168.APS_close() == 0)
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
            catch (Exception)
            {
                return false;
            }

        }

        [HandleProcessCorruptedStateExceptions]
        public void PointTableMove(Int32 _cardId, Int32 axis0, Int32 axis1, Double[] x, Double[] y, double vm, double acc)
        {
            PTSTS ptStatus = new PTSTS();
            PTLINE Line = new PTLINE();
            PTDWL dwell = new PTDWL();
            dwell.DwTime = 200;


            int cardid = _cardId;
            Int32 ptbId = 0, dimension = 2;
            int[] axisIdArray = new int[] { axis0, axis1 };

            int ret = APS168.APS_pt_disable(cardid, ptbId);
            ret = APS168.APS_pt_enable(cardid, ptbId, dimension, axisIdArray);

            ret = APS168.APS_pt_set_absolute(cardid, ptbId);
            ret = APS168.APS_pt_set_trans_buffered(cardid, ptbId);
            ret = APS168.APS_pt_set_acc(cardid, ptbId, acc);
            ret = APS168.APS_pt_set_dec(cardid, ptbId, acc);
            ret = APS168.APS_pt_set_vm(cardid, ptbId, vm);
            ret = APS168.APS_pt_set_ve(cardid, ptbId, vm);
            ret = APS168.APS_pt_set_s(cardid, ptbId, 0.5);
            for (int i = 0; i < x.Length; i++)
            {
                while (true)
                {

                    Line.Dim = dimension;

                    Line.Pos = new Double[] { Convert.ToDouble(x[i]), Convert.ToDouble(y[i]), 0, 0, 0, 0 };
                    ret = APS168.APS_pt_line(cardid, ptbId, ref Line, ref ptStatus);

                    break;

                }
            }
            APS168.APS_pt_start(cardid, 0);
            bool ptbFlag = true;
            while (ptbFlag)
            {
                int motionStatus = APS168.APS_motion_status(axisIdArray[0]);
                ret = APS168.APS_get_pt_status(cardid, ptbId, ref ptStatus);
                uint _bufRunningCnt = ptStatus.RunningCnt;
                if (_bufRunningCnt >= x.Length - 1)
                {
                    ptbFlag = false;
                }
                Thread.Sleep(100);
            }
            int cnt = 0;
            APS168.APS_get_trigger_count(cardid, 0, ref cnt);
        }

        [HandleProcessCorruptedStateExceptions]
        public void TwoDtrigger(Int32 _cardId, Int32 TGR_SRC, Int32 axis0, Int32 axis1, Double[] x, Double[] y, Int32 windows, Int32 width)
        {
            Int32 size;
            size = x.Length;
            //设置触发点
            const int TGR_MCMP0_SRC = 48;
            const int TGR_MCMP1_SRC = 49;
            APS168.APS_set_trigger_param(_cardId, TGR_MCMP0_SRC, axis0);
            APS168.APS_set_trigger_param(_cardId, TGR_MCMP1_SRC, axis1);
            switch (TGR_SRC)
            {
                case 0:
                    APS168.APS_set_trigger_param(_cardId, (Int32)APSDefine.TGR_TRG0_SRC, Convert.ToInt32("1000001", 2));
                    APS168.APS_set_trigger_param(_cardId, (Int32)APSDefine.TGR_TRG0_PWD, width);
                    APS168.APS_set_trigger_param(_cardId, (Int32)APSDefine.TGR_TRG0_LOGIC, 1);
                    APS168.APS_set_trigger_param(_cardId, (Int32)APSDefine.TGR_TRG_EN, Convert.ToInt32("0001", 2));
                    break;
                case 1:
                    APS168.APS_set_trigger_param(_cardId, (Int32)APSDefine.TGR_TRG1_SRC, Convert.ToInt32("1000001", 2));
                    APS168.APS_set_trigger_param(_cardId, (Int32)APSDefine.TGR_TRG1_PWD, width);
                    APS168.APS_set_trigger_param(_cardId, (Int32)APSDefine.TGR_TRG1_LOGIC, 0);
                    APS168.APS_set_trigger_param(_cardId, (Int32)APSDefine.TGR_TRG_EN, Convert.ToInt32("0010", 2));
                    break;
                case 2:
                    APS168.APS_set_trigger_param(_cardId, (Int32)APSDefine.TGR_TRG2_SRC, Convert.ToInt32("1000001", 2));
                    APS168.APS_set_trigger_param(_cardId, (Int32)APSDefine.TGR_TRG2_PWD, width);
                    APS168.APS_set_trigger_param(_cardId, (Int32)APSDefine.TGR_TRG2_LOGIC, 0);
                    APS168.APS_set_trigger_param(_cardId, (Int32)APSDefine.TGR_TRG_EN, Convert.ToInt32("0100", 2));
                    break;
                case 3:
                    APS168.APS_set_trigger_param(_cardId, (Int32)APSDefine.TGR_TRG3_SRC, Convert.ToInt32("1000001", 2));
                    APS168.APS_set_trigger_param(_cardId, (Int32)APSDefine.TGR_TRG3_PWD, width);
                    APS168.APS_set_trigger_param(_cardId, (Int32)APSDefine.TGR_TRG3_LOGIC, 0);
                    APS168.APS_set_trigger_param(_cardId, (Int32)APSDefine.TGR_TRG_EN, Convert.ToInt32("1000", 2));
                    break;
            }

            MCMP_POINT[] trPos = new MCMP_POINT[size];
            for (int i = 0; i < size; i++)
            {
                //trPos[i] = new MCMP_POINT(x[i], y[i], 0, 0, 0xf);
            }

            APS168.APS_set_multi_trigger_table(_cardId, 2, trPos, size, windows);
        }


        /// <summary>
        /// 获得某个输入端口的值(20408C)
        /// </summary>
        /// <param name="cardId"></param>
        /// <param name="port"></param>
        /// <returns></returns>
        //public bool GetDI(int port, int group = 0)
        //{
        //    bool ret = false;
        //    int inputValue = 0;
        //    try
        //    {

        //        //if (APS168.APS_read_d_input(_cardID, group, ref inputValue) == 0)//读取成功
        //        {
        //            int v = (inputValue >> port) & 1;
        //            if (v == 0)
        //            {
        //                ret = false;
        //            }
        //            else
        //            {
        //                ret = true;
        //            }
        //        }
        //        else//读取失败
        //        {
        //            throw new Exception("APS_read_d_input Err!");
        //        }
        //    }
        //    catch (Exception ex)
        //    {
        //        throw new Exception("APS_read_d_input Exception!" + ex.StackTrace);
        //    }
        //    return ret;
        //}
        //总线
        [HandleProcessCorruptedStateExceptions]
        public bool GetDI(int card, int port = 0)
        {
            bool ret = false;
            int inputValue = 0;
            try
            {

                int ret1 = APS168.APS_get_field_bus_d_channel_input(0, 0, card, port, ref inputValue);
                if (ret1 == 0)//读取成功APS168.APS_get_field_bus_d_channel_input(1, 0, card, port, ref inputValue) == 0
                {
                    if (inputValue == 0)
                    {
                        ret = false;
                    }
                    else
                    {
                        ret = true;
                    }
                }
                else//读取失败
                {
                    throw new Exception("APS_read_d_input Err!");
                }
            }
            catch (Exception ex)
            {
                throw new Exception("APS_read_d_input Exception!" + ex.StackTrace);
            }
            return ret;
        }
        /// <summary>
        /// 获得某个输出端口的值
        /// </summary>
        /// <param name="boardID"></param>
        /// <param name="port"></param>
        /// <returns></returns>
        //public bool GetDO(int port, int group = 0)
        //{
        //    int outputValue = 0;
        //    bool ret = false;
        //    try
        //    {
        //        if (APS168.APS_read_d_output(CardID, group, ref outputValue) == 0)//读取成功
        //        {
        //            if (((outputValue >> port) & 1) == 0)
        //            {
        //                ret = false;
        //            }
        //            else
        //            {
        //                ret = true;
        //            }
        //        }
        //        else//读取失败
        //        {
        //            throw new Exception("APS_read_d_output Err!");
        //        }
        //    }
        //    catch (Exception ex)
        //    {
        //        throw new Exception("APS_read_d_output Exception!" + ex.StackTrace);
        //    }
        //    return ret;
        //}
        [HandleProcessCorruptedStateExceptions]
        public bool GetDO(int card, int port = 0)
        {
            int outputValue = 0;
            bool ret = false;
            try
            {
                int ret1 = APS168.APS_get_field_bus_d_channel_output(0, 0, card, port, ref outputValue);
                if (ret1 == 0)//读取成功APS168.APS_get_field_bus_d_channel_output(1, 0, card, port, ref outputValue) == 0
                {
                    if (outputValue == 0)
                    {
                        ret = false;
                    }
                    else
                    {
                        ret = true;
                    }
                }
                else//读取失败
                {
                    throw new Exception("APS_read_d_output Err!");
                }
            }
            catch (Exception ex)
            {
                throw new Exception("APS_read_d_output Exception!" + ex.StackTrace);
            }
            return ret;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="boardID"></param>
        /// <param name="port"></param>
        /// <param name="ONOrOFF"></param>
        /// <returns></returns>
        //public bool SetDO(int port, int ONOrOFF, int group = 0)
        //{
        //    try
        //    {

        //        int ret = APS168.APS_write_d_channel_output(CardID, group, port, ONOrOFF);
        //        if (ret != 0)
        //        {
        //            return false;
        //        }
        //        else
        //        {
        //            return true;
        //        }
        //    }
        //    catch (Exception ex)
        //    {
        //        throw new Exception("APS_write_d_channel_output Err!" + ex.StackTrace);
        //    }
        //}
        [HandleProcessCorruptedStateExceptions]
        public bool SetDO(int submod, int port, int value)
        {
            try
            {
                int ret = APS168.APS_set_field_bus_d_channel_output(0, 0, submod, port, value);
                if (ret != 0)
                {
                    return false;
                }
                else
                {
                    return true;
                }
            }
            catch (Exception ex)
            {
                throw new Exception("APS_write_d_channel_output Err!" + ex.StackTrace);
            }
        }
        /// <summary>
        /// 急停
        /// It can stop single axis homing, positioning and speed moving.
        /// </summary>
        /// <param name="axisId">轴ID</param>
        /// <returns></returns>
        [HandleProcessCorruptedStateExceptions]
        public bool StopEmg(short axisId)
        {
            int? ret = 0;
            try
            {
                ret = APS168.APS_emg_stop(axisId);
                Thread.Sleep(100);
                double curPos = 0.0;
                ret += APS168.APS_get_position_f(axisId, ref curPos);
                ret += APS168.APS_set_command_f(axisId, curPos);
                if (ret != 0)
                {
                    return false;
                }
            }
            catch (Exception ex)
            {
                throw new Exception("StopEmg Exception(axisId:" + axisId + ")! " + ex.StackTrace);
            }
            return true;
        }
        /// <summary>
        /// 减速停止
        ///  It can stop single axis homing, positioning and speed moving. 
        /// </summary>
        /// <param name="axisId">轴号</param>
        /// <param name="acc"></param>
        /// <returns>true:成功；false：失败；异常抛出</returns>
        [HandleProcessCorruptedStateExceptions]
        public bool StopMove(short axisId, double acc)
        {
            int? ret = 0;

            try
            {
                //ret += APS168.APS_set_axis_param_f(axisId, (Int32)APSDefine.PRA_STP_DEC, acc);
                ret += APS168.APS_stop_move((int)axisId);


                if (ret != 0)
                {
                    return false;
                }
            }
            catch (Exception ex)
            {
                throw new Exception("StopMove Exception(axisId:" + axisId + ")! " + ex.StackTrace);
            }
            return true;
        }
        /// <summary>
        /// 多轴直线插补运动
        /// </summary>
        /// <param name="axisIdArray"></param>
        /// <param name="axisPosArray"></param>
        /// <param name="APSOPTION"></param>
        /// <param name="vm"></param>
        /// <param name="acc"></param>
        /// <param name="dec"></param>
        /// <param name="SF"></param>
        /// <returns></returns>
        [HandleProcessCorruptedStateExceptions]
        public bool InterPolationLine(int[] axisIdArray, double[] axisPosArray, PRA_OPTION_ENUM apsOption, double vm, double acc = 0.1, double dec = 0.1, PRA_SF_ENUM SF = PRA_SF_ENUM.S_CURVE)
        {
            int? ret = 0;
            double[] positionArray = new double[10];
            double[] Vm = new double[10];
            double[] Acc = new double[10];
            double[] Dec = new double[10];
            double transPara = 0.0;
            ASYNCALL wait = new ASYNCALL();


            try
            {
                if (axisIdArray.Length == axisPosArray.Length)
                {
                    for (int axisNumIndex = 0; axisNumIndex < axisPosArray.Length; axisNumIndex++)
                    {
                        Vm[axisNumIndex] = vm ;
                        Acc[axisNumIndex] = Vm[axisNumIndex] / acc;
                        Dec[axisNumIndex] = Vm[axisNumIndex] / dec;
                        positionArray[axisNumIndex] = axisPosArray[axisNumIndex];

                        ret += APS168.APS_set_axis_param(axisIdArray[axisNumIndex], (Int32)APSDefine.PRA_SF, (Int32)SF);
                        ret += APS168.APS_set_axis_param_f(axisIdArray[axisNumIndex], (Int32)APSDefine.PRA_ACC, Acc[axisNumIndex]);
                        ret += APS168.APS_set_axis_param_f(axisIdArray[axisNumIndex], (Int32)APSDefine.PRA_DEC, Dec[axisNumIndex]);
                        ret += APS168.APS_set_axis_param_f(axisIdArray[axisNumIndex], (Int32)APSDefine.PRA_VM, Vm[axisNumIndex]);
                    }
                    //ret += APS168.APS_line(axisIdArray.Length, axisIdArray, (int)apsOption, positionArray, ref transPara, ref wait);
                    P2PMoveWait(axisIdArray, positionArray, apsOption, Vm, Acc, Dec);
                    if (ret != 0)
                    {
                        //m_Logger.Error("轴" + axisIdArray[axisNumIndex] + "InterPolationLine失败！");
                        //return false;
                    }
                }
            }
            catch (Exception ex)
            {
                //m_Logger.Error("多轴直线插补运动失败！" + ex.StackTrace);
                return false;
            }
            return true;
        }

        /// <summary>
        /// 获取急停状态
        /// </summary>
        /// <param name="axisId"></param>
        /// <returns></returns>
        [HandleProcessCorruptedStateExceptions]
        public bool GetEmgStatus(short axisId)
        {
            try
            {
                if (((APS168.APS_motion_io_status(Convert.ToInt16(axisId)) >> (int)ADLINK_MOTION_IO_STATUS_ENUM.MIO_EMG) & 1) == 1)
                    return true;
                else
                    return false;
            }
            catch (Exception ex)
            {
                throw new Exception("Adlink GetEmgStatus Exception! " + ex.StackTrace);
            }
        }
        /// <summary>
        /// 获取轴的报警状态（Motion IO status 的第0位）
        /// </summary>
        /// <param name="axisId"></param>
        /// <returns></returns>
        [HandleProcessCorruptedStateExceptions]
        public bool GetAxisAlarmStatus(short axisId)
        {
            try
            {
                if (((APS168.APS_motion_io_status(Convert.ToInt16(axisId)) >> (int)ADLINK_MOTION_IO_STATUS_ENUM.MIO_ALM) & 1) == 1)
                    return true;
                else
                    return false;
            }
            catch (Exception ex)
            {
                throw new Exception("Adlink GetAxisAlarmStatus Exception! " + ex.StackTrace);
            }
        }
        /// <summary>
        /// 获取轴的负限位状态（Motion IO status 的第2位）
        /// </summary>
        /// <param name="axisId"></param>
        /// <returns></returns>
        [HandleProcessCorruptedStateExceptions]
        public bool GetAxisMelStatus(short axisId)
        {
            try
            {
                if (((APS168.APS_motion_io_status(Convert.ToInt16(axisId)) >> (int)ADLINK_MOTION_IO_STATUS_ENUM.MIO_MEL) & 1) == 1)
                    return true;
                else
                    return false;
            }
            catch (Exception ex)
            {
                throw new Exception("Adlink GetAxisMelStatus Exception! " + ex.StackTrace);
            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="axisId"></param>
        /// <returns></returns>
        [HandleProcessCorruptedStateExceptions]
        public bool GetAxisPelStatus(short axisId)
        {
            try
            {
                if (((APS168.APS_motion_io_status(Convert.ToInt16(axisId)) >> (int)ADLINK_MOTION_IO_STATUS_ENUM.MIO_PEL) & 1) == 1)
                    return true;
                else
                    return false;
            }
            catch (Exception ex)
            {
                throw new Exception("Adlink GetAxisPelStatus Exception! " + ex.StackTrace);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="axisId"></param>
        /// <param name="apsOption"></param>
        /// <param name="jogVm"></param>
        /// <param name="jogAcc"></param>
        /// <returns></returns>
        [HandleProcessCorruptedStateExceptions]
        public bool JogMoveStart(short axisId, DIR_ENUM apsOption, double jogVm, double jogAcc)
        {
            int? ret = null;
            try
            {
                ret += APS168.APS_set_axis_param(axisId, (Int32)APSDefine.PRA_JG_MODE, 0);
                ret += APS168.APS_set_axis_param(axisId, (Int32)APSDefine.PRA_JG_DIR, (int)apsOption);

                ret += APS168.APS_set_axis_param_f(axisId, (Int32)APSDefine.PRA_JG_CURVE, 0.0);
                ret += APS168.APS_set_axis_param_f(axisId, (Int32)APSDefine.PRA_JG_ACC, jogAcc);
                ret += APS168.APS_set_axis_param_f(axisId, (Int32)APSDefine.PRA_JG_DEC, jogAcc);
                ret += APS168.APS_set_axis_param_f(axisId, (Int32)APSDefine.PRA_JG_VM, jogVm);
                // Create a rising edge.
                ret += APS168.APS_jog_start(axisId, OFF);
                ret += APS168.APS_jog_start(axisId, ON);
                if (ret != 0)
                {
                    return false;
                }
            }
            catch (Exception ex)
            {
                return false;
            }
            return true;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="axisId"></param>
        /// <returns></returns>
        [HandleProcessCorruptedStateExceptions]
        public bool JogMoveStop(short axisId)
        {
            int? ret = null;
            try
            {
                ret += APS168.APS_jog_start((int)axisId, ON);  //Jog On
                ret += APS168.APS_jog_start((int)axisId, OFF);  //Jog Off
                if (ret != 0)
                {
                    return false;
                }
            }
            catch (Exception ex)
            {
                return false;
            }
            return true;
        }


        /// <summary>
        /// 获取电机实际位置
        /// </summary>
        /// <param name="axisId">轴ID</param>
        /// <param name="position">实际位置</param>
        /// <returns></returns>
        [HandleProcessCorruptedStateExceptions]
        public bool GetPosition(short axisId, ref double position)
        {
            int? ret = null;
            // axisMagnification = new MAGNIFICATION[2000];
            double PositionFun = 0;
            try
            {
                ret = APS168.APS_get_position_f(Convert.ToInt16(axisId), ref PositionFun);

                if (ret != 0)
                {
                    //m_Logger.Error("Fail to get axis's current position");
                    return false;
                }
            }
            catch (Exception e)
            {
                //m_Logger.Error("Get axis's  current position exception!" + e.Message);
                return false;
            }
            return true;
        }


        /// <summary>
        /// 失能所有轴
        /// </summary>
        [HandleProcessCorruptedStateExceptions]
        public bool ServoOff(int axisId)
        {
            try
            {
                return (APS168.APS_set_servo_on(axisId, OFF) == 0);
            }
            catch (Exception ex)
            {
                throw new Exception("Adlink ServoOff Exception !" + ex.StackTrace);
            }
        }
        /// <summary>
        /// 使能所有轴
        /// </summary>
        [HandleProcessCorruptedStateExceptions]
        public bool ServoON(int axisId)
        {
            try
            {
                return (APS168.APS_set_servo_on(axisId, ON) == 0);
            }
            catch (Exception ex)
            {
                throw new Exception("Adlink ServoON Exception !" + ex.StackTrace);
            }
        }
        /// <summary>
        /// 检查轴是否在运动
        /// </summary>
        /// <param name="axisId"></param>
        /// <returns></returns>
        [HandleProcessCorruptedStateExceptions]
        public bool IsMoving(int axisId)
        {
            return (!CheckMoveDone((short)axisId));
        }

        /// <summary>
        /// 检测运动是否完成
        /// </summary>
        /// <param name="axisId"></param>
        /// <returns></returns>
        [HandleProcessCorruptedStateExceptions]
        public bool CheckMoveDone(short axisId)
        {
            int stopCode = 0;
            // Get motion done bit,normal stop
            int status = APS168.APS_motion_status(axisId);
            int isMotionDone = (status >> (int)APSDefine.NSTP) & 1; //normal stop                
            if (1 == isMotionDone)//正常停止后，二次检查停止原因
            {
                //abnormal stop
                status = ((APS168.APS_motion_status(axisId) >> (int)APSDefine.MTS_ASTP)) & 1;
                if (status == 1)//abnormal stop
                {
                    //用APS_get_stop_code获取停止原因：
                    //Symbol              Code      Description             
                    //STOP_NORMAL          0        Stop normally             
                    //STOP_EMG             1        Stop when EMG is turn ON             
                    //STOP_ALM             2        Stop when ALM is turn ON             
                    //STOP_SVNO            3        Stop when servo is turn - OFF             
                    //STOP_PEL             4        Stop by PEL signal turn ON            
                    //STOP_MEL             5        Stop by MEL signal turn ON             
                    //STOP_SPEL            6        Stop by soft - limit condition – positive end limit             
                    //STOP_SMEL            7        Stop by soft - limit condition – minus end limit             
                    //STOP_USER_EMG        8        EMG stop by user              
                    //STOP_USER            9        Stop by user             
                    //STOP_GAN_L1          10       Stop by E - Gear gantry protect level 1 condition is met.            
                    //STOP_GAN_L2          11       Stop by E - Gear gantry protect level 2 condition is met            
                    //STOP_GEAR_SLAVE      12       Stop because gear slave axis             
                    //STOP_ERROR_LEVEL     13       Error position check level            
                    //STOP_DI              14       DI            
                    //APS168.APS_get_stop_code(axisId, ref stopCode);
                }

                if (stopCode != 0)
                {
                    throw new Exception("Adlink CheckMoveDone " + Enum.GetName(typeof(ADLINK_STOP_CODE_ENUM), stopCode) + " !");
                }
                else
                {
                    return true;
                }
            }

            return false;//in motion
        }

        [HandleProcessCorruptedStateExceptions]
        public bool SetPos(int axisId, double pos)
        {
            int ret = 0;
            try
            {
                ret = APS168.APS_set_position_f(axisId, pos);
                if (ret != 0)
                {
                    return false;
                }
                else
                {
                    return true;
                }
            }
            catch (Exception)
            {
                throw new Exception("APS_set_position_f Exception!");
            }
        }

        //点到点移动(模式可供选择：绝对移动、相对移动）
        [HandleProcessCorruptedStateExceptions]
        public void P2PMoveWait(int[] axisIdArray, double[] axisPosArray, PRA_OPTION_ENUM apsOption, double[] vm, double[] acc, double[] dec)
        {
            int ret = 0;
            for (int i = 0; i < axisIdArray.Length; i++)
            {
                int axisId = axisIdArray[i];
                ASYNCALL p = new ASYNCALL();

                ret = APS168.APS_set_axis_param_f(axisId, (Int32)APSDefine.PRA_VM, vm[i]);
                ret += APS168.APS_set_axis_param_f(axisId, (Int32)APSDefine.PRA_ACC, acc[i]);
                ret += APS168.APS_set_axis_param_f(axisId, (Int32)APSDefine.PRA_DEC, dec[i]);
                ret += APS168.APS_ptp(axisId, (int)apsOption, (int)(axisPosArray[i]), ref p);
            }



        }
        [HandleProcessCorruptedStateExceptions]
        public static void CmpTrigger(Int32 CH, Int32 StartPoint, Int32 RepeatTimes, Int32 Interval)
        {

            //Int32 ret = 0;
            //Int32 Board_ID = 0;

            //// Enable trigger output

            //    ret = APS168.APS_set_trigger_param(Board_ID, (Int32)APSDefine.TGR_TRG_EN, 0xf);

            ////Trigger output TRG0 ~ TRG3 source
            ////Bit 0: Manual 
            ////Bit 1: Reserved
            ////Bit 2: FCMP0 
            ////Bit 3: FCMP1 
            ////Bit 4: LCMP0 
            ////Bit 5: LCMP1
            //ret = APS168.APS_set_trigger_param(Board_ID, (Int32)APSDefine.TGR_TRG0_SRC, 0x1);
            //ret = APS168.APS_set_trigger_param(Board_ID, (Int32)APSDefine.TGR_TRG1_SRC, 0x1);
            //ret = APS168.APS_set_trigger_param(Board_ID, (Int32)APSDefine.TGR_TRG2_SRC, 0x1);
            //ret = APS168.APS_set_trigger_param(Board_ID, (Int32)APSDefine.TGR_TRG3_SRC, 0x1);

            //ret = APS168.APS_set_trigger_linear(Board_ID, CH, StartPoint, RepeatTimes, Interval);
            //    //ret = APS168.APS_set_trigger_manual(Board_ID, CH);

            //// Disable TRG 0 ~ 3
            //ret = APS168.APS_set_trigger_param(Board_ID, (Int32)APSDefine.TGR_TRG_EN, 0);

            ////Disable all CMP
            //ret = APS168.APS_set_trigger_param(Board_ID, (Int32)APSDefine.TGR_TRG0_SRC, 0);
            //ret = APS168.APS_set_trigger_param(Board_ID, (Int32)APSDefine.TGR_TRG1_SRC, 0);
            //ret = APS168.APS_set_trigger_param(Board_ID, (Int32)APSDefine.TGR_TRG2_SRC, 0);
            //ret = APS168.APS_set_trigger_param(Board_ID, (Int32)APSDefine.TGR_TRG3_SRC, 0);


            Int32 ret = 0;
            Int32 Board_ID = 0;
            ////Stop Timer
            //ret = APS168.APS_set_trigger_param(Board_ID, (Int32)APSDefine.TIMR_EN, 0);

            ////Clear timer
            //ret = APS168.APS_set_timer_counter(Board_ID, 0, 0);

            //// Disable TRG 0 ~ 3
            //ret = APS168.APS_set_trigger_param(Board_ID, (Int32)APSDefine.TGR_TRG_EN, 0);

            //// Disable all CMP
            ////ret = APS168.APS_set_trigger_param(Board_ID, (Int32)APSDefine.TGR_TRG0_SRC, 0);
            ////ret = APS168.APS_set_trigger_param(Board_ID, (Int32)APSDefine.TGR_TRG1_SRC, 0);
            //ret = APS168.APS_set_trigger_param(Board_ID, (Int32)APSDefine.TGR_TRG2_SRC, 0);
            ////ret = APS168.APS_set_trigger_param(Board_ID, (Int32)APSDefine.TGR_TRG3_SRC, 0);

            //-----------------------------------------------------------

            // Enable TRG 0 ~ 3

            ret = APS168.APS_set_trigger_param(Board_ID, (Int32)APSDefine.TGR_TRG_EN, 0xf);

            //Linear compare source: Timer counter 
            // ret = APS168.APS_set_trigger_param(Board_ID, (Int32)APSDefine.TGR_LCMP0_SRC, 6);
            //ret = APS168.APS_set_trigger_param(Board_ID, (Int32)APSDefine.TGR_LCMP1_SRC, 8);


            //ret = APS168.APS_set_trigger_param(Board_ID, (Int32)APSDefine.TGR_LCMP2_SRC, 8);
            //Trigger output TRG0 ~ TRG3 source
            //Trigger output 0 source: LCMP0 
            //Trigger output 1 source: LCMP0 
            //Trigger output 2 source: LCMP1 
            //Trigger output 3 source: LCMP1
            ret = APS168.APS_set_trigger_param(Board_ID, (Int32)APSDefine.TGR_TRG0_SRC, 0x10);
            ret = APS168.APS_set_trigger_param(Board_ID, (Int32)APSDefine.TGR_TRG1_SRC, 0x10);
            ret = APS168.APS_set_trigger_param(Board_ID, (Int32)APSDefine.TGR_TRG2_SRC, 0x10);
            ret = APS168.APS_set_trigger_param(Board_ID, (Int32)APSDefine.TGR_TRG3_SRC, 0x10);
            //ret = APS168.APS_set_trigger_param(0, 0x06, 0xf); //Enable LCMP0

            ret = APS168.APS_set_trigger_param(Board_ID, (Int32)APSDefine.TGR_TRG2_PWD, 40000);
            ret = APS168.APS_set_trigger_param(Board_ID, (Int32)APSDefine.TGR_TCMP0_DIR, 1);
            ret = APS168.APS_set_trigger_param(Board_ID, (Int32)APSDefine.TGR_TRG2_LOGIC, 0);
            ret = APS168.APS_set_trigger_param(Board_ID, (Int32)APSDefine.TGR_TRG2_TGL, 1);

            // APS168.APS_set_trigger_param(Board_ID, (Int32)APSDefine.TIG_LCMP2_SRC, 1);
            // APS168.APS_set_trigger_param(Board_ID, (Int32)APSDefine.TIG_LCMP6_SRC, 1);
            //Start linear CMP

            ret = APS168.APS_set_trigger_linear(Board_ID, 0, StartPoint, RepeatTimes, Interval);

            ////Timer Interval: 1ms
            //ret = APS168.APS_set_trigger_param(Board_ID, (Int32)APSDefine.TIMR_ITV, 10000);

            ////TIMR DIR: Positive count
            //ret = APS168.APS_set_trigger_param(Board_ID, (Int32)APSDefine.TIMR_DIR, 0);

            ////Start Timer
            //ret = APS168.APS_set_trigger_param(Board_ID, (Int32)APSDefine.TIMR_EN, 1);

        }
        [HandleProcessCorruptedStateExceptions]
        public static void CmpTrigger(Int32 CH)
        {


            Int32 ret = 0;
            Int32 Board_ID = 0;
            //Int32 ch1 = 0;
            //ch1 = CH;
            // Enable TRG 0 ~ 3

            ret = APS168.APS_set_trigger_param(Board_ID, (Int32)APSDefine.TGR_TRG_EN, 0xf);


            //Trigger output TRG0 ~ TRG3 source
            //Trigger output 0 source: LCMP0 
            //Trigger output 1 source: LCMP0 
            //Trigger output 2 source: LCMP1 
            //Trigger output 3 source: LCMP1
            //ret = APS168.APS_set_trigger_manual(Board_ID, ch1);
            ret = APS168.APS_set_trigger_param(Board_ID, (Int32)APSDefine.TGR_TRG0_SRC, 0x1);
            ret = APS168.APS_set_trigger_param(Board_ID, (Int32)APSDefine.TGR_TRG1_SRC, 0x1);
            ret = APS168.APS_set_trigger_param(Board_ID, (Int32)APSDefine.TGR_TRG2_SRC, 0x1);
            ret = APS168.APS_set_trigger_param(Board_ID, (Int32)APSDefine.TGR_TRG3_SRC, 0x1);
            // ret = APS168.APS_set_trigger_param(0, 0x06, 0xf); //Enable LCMP0


            //ret = APS168.APS_set_trigger_param(Board_ID, (Int32)APSDefine.TGR_TRG0_PWD, 200);
            //ret = APS168.APS_set_trigger_param(Board_ID, (Int32)APSDefine.TGR_TRG1_PWD, 200);
            //ret = APS168.APS_set_trigger_param(Board_ID, (Int32)APSDefine.TGR_TRG2_PWD, 200);
            //ret = APS168.APS_set_trigger_param(Board_ID, (Int32)APSDefine.TGR_TRG3_PWD, 200);

            ret = APS168.APS_set_trigger_param(Board_ID, (Int32)APSDefine.TGR_TRG0_PWD, 200);
            ret = APS168.APS_set_trigger_param(Board_ID, (Int32)APSDefine.TGR_TRG1_PWD, 200);
            ret = APS168.APS_set_trigger_param(Board_ID, (Int32)APSDefine.TGR_TRG2_PWD, 200);
            ret = APS168.APS_set_trigger_param(Board_ID, (Int32)APSDefine.TGR_TRG3_PWD, 200);

            ret = APS168.APS_set_trigger_param(Board_ID, (Int32)APSDefine.TGR_TCMP0_DIR, 1);
            ret = APS168.APS_set_trigger_param(Board_ID, (Int32)APSDefine.TGR_TRG0_LOGIC, 1);
            ret = APS168.APS_set_trigger_param(Board_ID, (Int32)APSDefine.TGR_TRG1_LOGIC, 1);
            ret = APS168.APS_set_trigger_param(Board_ID, (Int32)APSDefine.TGR_TRG0_TGL, 0);
            ret = APS168.APS_set_trigger_param(Board_ID, (Int32)APSDefine.TGR_TRG1_TGL, 0);
            ret = APS168.APS_set_trigger_param(Board_ID, (Int32)APSDefine.TGR_TRG2_TGL, 0);
        }
        //int[] mcmp = new int[4] { (Int32)APSDefine.TGR_MCMP0_SRC, (Int32)APSDefine.TGR_MCMP1_SRC, (Int32)APSDefine.TGR_MCMP2_SRC, (Int32)APSDefine.TGR_MCMP3_SRC };
        /// <summary>
        /// 触发计数清零
        /// </summary>
        /// <param name="board">板卡卡号</param>
        /// <param name="channel">开始触发通道号</param>
        /// <param name="num">清零数量</param>
        /// <returns></returns>
        [HandleProcessCorruptedStateExceptions]
        public void TriggleZeroCount(int board, int[] channel, int num)
        {
            for (int i = 0; i < num; i++)
            {
                int result = APS168.APS_reset_trigger_count(board, channel[i]); //板卡号，通道号
            }
        }

        /// <summary>
        /// 关闭脉冲触发
        /// </summary>
        /// <param name="board">板卡号</param>
        /// <param name="num">触发通道数量 8254 =2，8258=4</param>
        //public void TriggerStop(int board, int num)
        //{
        //    // Disable TRG 0 ~ 3
        //    int ret = 0;
        //    ret = APS168.APS_set_trigger_param(board, (Int32)APSDefine.TGR_TRG_EN, 0);              //关闭脉冲触发

        //    // Disable all CMP   
        //    for (int i = 0; i < num; i++)
        //    {
        //        ret = APS168.APS_set_trigger_param(board, source[i], 0);            //关闭脉冲触发来源
        //    }
        //}
        /// <summary>
        /// 触发初始化
        /// </summary>
        /// <param name="board">板卡号</param>
        /// <param name="channelstart">开启通道（这个是由4位二进制表示，比如0001:表示0通道启触发，0011:表示0、1通道开启触发）</param>
        /// <param name="channel">触发通道（）</param>
        /// <param name="num">通道数量2或4</param>
        /// <param name="value">触发来源(Bit 0:Manual0,Bit 1:Reserved,Bit 2:FCMP0,Bit 3:FCMP1,Bit 4:LCMP0,Bit 5:LCMP1,Bit 6:MCMP),比如通道0手动0000001，0x1</param>
        /// <param name="width">脉冲宽度(时间=num*20us)</param>
        /// <param name="model">触发模式（0:手动触发，1:线性触发2:表比较触发3，多轴触发）</param>
        /// <param name="encoder">触发编码器号（编码器号：0-7 ，8：时间触发 9:禁用）</param>
        /// <param name="tdirection">表比较方向（0：Negative  ，1：Positive 2:Bi-direction）</param>
        /// <param name="toggle">触发方式切换（0：Pulse out  ，1：Toggle out </param>
        [HandleProcessCorruptedStateExceptions]
        public static void TriggerIni(int board, int channelstart, int channel, int num, int value, int width, int model, int encoder, int tdirection, int toggle) //    
        {
            int ret = 0;
            //int[] channel = new int[4] { 0, 1, 2, 4 };
            int[] source = new int[4] { (Int32)APSDefine.TGR_TRG0_SRC, (Int32)APSDefine.TGR_TRG1_SRC, (Int32)APSDefine.TGR_TRG2_SRC, (Int32)APSDefine.TGR_TRG3_SRC };
            int[] line = new int[4] { (Int32)APSDefine.TGR_LCMP0_SRC, (Int32)APSDefine.TGR_LCMP0_SRC, (Int32)APSDefine.TGR_LCMP0_SRC, (Int32)APSDefine.TGR_LCMP0_SRC };
            int[] table = new int[4] { (Int32)APSDefine.TGR_TCMP0_SRC, (Int32)APSDefine.TGR_TCMP1_SRC, (Int32)APSDefine.TGR_TCMP0_SRC, (Int32)APSDefine.TGR_TCMP1_SRC };
            int[] direct = new int[4] { (Int32)APSDefine.TGR_TCMP0_DIR, (Int32)APSDefine.TGR_TCMP1_DIR, (Int32)APSDefine.TGR_TCMP0_DIR, (Int32)APSDefine.TGR_TCMP1_DIR };
            // Enabel all CMP source
            // Enable trigger output
            ret = APS168.APS_set_trigger_param(board, (Int32)APSDefine.TGR_TRG_EN, channelstart);
            for (int i = 0; i < num; i++)
            {
                ret = APS168.APS_set_trigger_param(board, source[i], value);
            }
            //ret = APS168.APS_set_trigger_param(board, direct[channel], tdirection);//表比较方向
            ret = APS168.APS_set_trigger_param(board, (Int32)APSDefine.TGR_TRG2_PWD, width);
            ret = APS168.APS_set_trigger_param(board, (Int32)APSDefine.TGR_TRG2_PWD, width);
            ret = APS168.APS_set_trigger_param(board, (Int32)APSDefine.TGR_TRG2_TGL, toggle); //触发方式切换  0:脉冲触发 1:外部触发
            ret = APS168.APS_set_trigger_param(board, (Int32)APSDefine.TGR_TRG2_TGL, toggle); //触发方式切换  0:脉冲触发 1:外部触发
            if (model == 1)
            {
                ret = APS168.APS_set_trigger_param(board, line[channel], encoder);//卡号，通道号(0-1)，编码器编号  
            }
            else if (model == 2)
            {
                ret = APS168.APS_set_trigger_param(board, table[channel], encoder);//卡号，通道号(0-1)，编码器编号
            }
            else if (model == 3)
            {
                for (int i = 0; i < num; i++)
                {
                    //ret = APS168.APS_set_trigger_param(board, mcmp[i], i);
                }

                ret = APS168.APS_set_trigger_param(board, (Int32)APSDefine.TGR_TRG0_TGL, toggle); //触发方式切换  0:脉冲触发 1:外部触发
                ret = APS168.APS_set_trigger_param(board, (Int32)APSDefine.TGR_TRG1_TGL, toggle); //触发方式切换  0:脉冲触发 1:外部触发

                ret = APS168.APS_set_trigger_param(board, table[0], 0);  //
            }
            ret = APS168.APS_set_trigger_linear(0, 2, 10, 1000, 10);
        }

        public bool StartGear(short axisId, GEAR_MODE mode)
        {
            throw new NotImplementedException();
        }

        public bool IsHoming(int axisID)
        {
            return IsMoving(axisID);
        }
        /// <summary>
        /// 清除报警
        /// </summary>
        /// <param name="axisId"></param>
        /// <returns></returns>
        public bool ClearAlarm(short axisId)
        {
            try
            {
                int ret = APS168.APS_reset_field_bus_alarm(axisId);//清除报警
                Thread.Sleep(100);
                if (ret == 0)
                {
                    bool isAlarm = GetALMStatus(axisId);//清除成功后，读取报警状态
                    if (isAlarm == false)
                    {
                        return true;
                    }
                }
            }
            catch (Exception ex)
            {
                new Exception("Adlink833X ClearAlarm Exception !" + ex.StackTrace);
            }
            return false;
        }

        public void UpdateSlaveResource(ref ICard card, int mode = 0)
        {
            throw new NotImplementedException();
        }
    }
}